"""
	doc: https://ascendex.github.io/ascendex-pro-api
"""
import base64
import hashlib
import hmac
import time
from ubroker import SpotBroker


class AscendEXSpot(SpotBroker):
	intervals = ('1', '5', '15', '30', '60', '1d', '1w', '1m')
	status = dict(
		New=SpotBroker.Created, PendingNew=SpotBroker.Created,
		Filled=SpotBroker.Filled, PartiallyFilled=SpotBroker.Partial,
		Canceled=SpotBroker.Canceled, Rejected=SpotBroker.Rejected
	)
	
	def __init__(self, **params):
		super().__init__('https://ascendex.com', **params)
	
	def order_format(self, order):
		return dict(
			id=order['orderId'], symbol=order['symbol'], time=order['lastExecTime'],
			side=SpotBroker.Buy if order['side'] == 'Buy' else SpotBroker.Sell, price=order['price'],
			quantity=order['orderQty'], traded_quantity=order['cumFilledQty'],
			state=self.status[order['status']]
		)
	
	@staticmethod
	def trade_format(trade):
		return dict(
			id=trade['seqNum'], time=trade['lastExecTime'],
			side=SpotBroker.Buy if trade['side'] == 'Buy' else SpotBroker.Sell,
			price=trade['avgPx'], order_id=trade['orderId'], symbol=trade['symbol'], quantity=trade['cumFilledQty'],
			commission=trade['cumFee'], commission_asset=trade['feeAsset']
		)
	
	def sign(self, path, **kwargs):
		timestamp = str(int((time.time() + 5) * 1000))
		payload = timestamp + path
		signature = hmac.new(
			self.params['secret'].encode('utf-8'), payload.encode('utf-8'), digestmod=hashlib.sha256
		).digest()
		signature = base64.b64encode(signature).decode()
		self.headers.update({
			'x-auth-key': self.params['key'], 'x-auth-signature': signature, 'x-auth-timestamp': timestamp
		})
		return kwargs
	
	async def http_requests(self, method, path, **kwargs):
		response = await super().http_requests(method, path, **kwargs)
		if response.get('code'):
			raise ValueError(response)
		return response.get('data')
	
	async def basic(self):
		path = '/api/pro/v1/cash/products'
		response = await self.http_requests(SpotBroker.GET, path)
		return [dict(
			base=item['symbol'].split('/')[0], quote=item['symbol'].split('/')[1], symbol=item['symbol'],
			price_tick=item['tickSize'], min_quantity=item['lotSize'], min_notional=item['minNotional']
		) for item in response]
	
	async def depth(self, symbol):
		path = '/api/pro/v1/depth'
		response = await self.http_requests(SpotBroker.GET, path, params=dict(symbol=symbol))
		return response['data']
	
	async def kline(self, symbol, interval):
		path = '/api/pro/v1/barhist'
		response = await self.http_requests(SpotBroker.GET, path, params=dict(
			symbol=symbol, n=500, interval=self.intervals[SpotBroker.CandleIntervals.index(interval)]
		))
		return [[
			item['data']['ts'], item['data']['o'], item['data']['h'], item['data']['l'],
			item['data']['c'], item['data']['v']
		] for item in response]
	
	async def trade(self, symbol):
		path = '/api/pro/v1/trades'
		response = await self.http_requests(SpotBroker.GET, path, params=dict(symbol=symbol))
		return [dict(
			time=item['ts'], side=SpotBroker.Buy if item['bm'] else SpotBroker.Sell, price=item['p'], quantity=item['q']
		) for item in response['data'][::-1]]
	
	async def ticker(self, symbol):
		path = '/api/pro/v1/spot/ticker'
		response = await self.http_requests(SpotBroker.GET, path, params=dict(symbol=symbol))
		return dict(
			last=response['close'], low24h=response['low'], open24h=response['open'],
			high24h=response['high'], volume24h=response['volume']
		)
	
	async def balance(self):
		path, params = '/%s/api/pro/v1/cash/balance' % self.params['passphrase'], self.sign(path='balance')
		response = await self.http_requests(SpotBroker.GET, path, params=params)
		return {item['asset']: dict(
			available=item['availableBalance'], frozen=float(item['totalBalance']) - float(item['availableBalance'])
		) for item in response}
	
	async def create_order(self, symbol, mold, side, quantity, line=None, direction=None, price=None):
		path = '/%s/api/pro/v1/cash/order' % self.params['passphrase']
		params = self.sign(
			path='order', time=int(time.time() * 1000), symbol=symbol, side=side,
			orderPrice=self.decimal_to_string(price), orderQty=self.decimal_to_string(quantity), orderType='limit',
			timeInForce='GTC', respInst='ACCEPT'
		)
		response = await self.http_requests(SpotBroker.GET, path, json=params)
		return response['info']['orderId']
	
	async def cancel_order(self, order_id, symbol):
		path = '/%s/api/pro/v1/cash/order' % self.params['passphrase']
		params = self.sign(path='order', time=int(time.time() * 1000), symbol=symbol, orderId=order_id)
		response = await self.http_requests(SpotBroker.DELETE, path, json=params)
		return response['status'] == 'Ack'
	
	async def order_detail(self, order_id, symbol):
		path = '/%s/api/pro/v1/cash/order/status' % self.params['passphrase']
		params = self.sign(path='order/status', orderId=order_id)
		response = await self.http_requests(SpotBroker.GET, path, params=params)
		return self.order_format(response)
	
	async def active_orders(self, symbol):
		path = '/%s/api/pro/v1/cash/order/open' % self.params['passphrase']
		params = self.sign(path='order/open', symbol=symbol)
		response = await self.http_requests(SpotBroker.GET, path, params=params)
		return [self.order_format(order) for order in response]
	
	async def history_orders(self, symbol, start, end):
		path = '/%s/api/pro/v1/cash/order/hist/current' % self.params['passphrase']
		params = self.sign(path='order/hist/current', symbol=symbol)
		response = await self.http_requests(SpotBroker.GET, path, params=params)
		return [self.order_format(order) for order in response]
	
	async def history_trades(self, symbol, start, end):
		path = '/%s/api/pro/v1/cash/order/hist/current' % self.params['passphrase']
		params = self.sign(path='order/hist/current', symbol=symbol)
		response = await self.http_requests(SpotBroker.GET, path, params=params)
		return [self.trade_format(order) for order in response if float(order['cumFilledQty']) > 0]
